﻿using System;
using System.Linq;

namespace ForceSystem.Untangler
{
    public class UntangledType
    {
        public UntangledContext Context { get; private set; }

        public UntangledAssembly Assembly { get; private set; }

        public Type Type { get; private set; }

        public string Namespace { get { return Type.Namespace; } }
        public string Name      { get { return Type.Name; } }
        public string FullName  { get { return Type.FullName; } }

        public UntangledTypeCollection DerivedTypes
        {
            get
            {
                if (_derivedTypes == null)
                    CacheDerivedTypes();

                return _derivedTypes;
            }
        }

        /// <summary>
        /// Check given type is derived
        /// </summary>
        /// <param name="subject"></param>
        /// <returns></returns>
        public bool IsDerivedType(UntangledType subject)
        {
            // Check base type.
            var baseType = subject.Type.BaseType;

            var derived = (baseType == Type) ||
                            (baseType != null && baseType.IsGenericType && baseType.GetGenericTypeDefinition() == Type);

            if (derived)
                return true;

            // Check implementation.



            return false;
        }

        /// <summary>
        /// Caceh derived types list.
        /// </summary>
        private void CacheDerivedTypes()
        {
            var types = from t in Context.Types
                        where IsDerivedType(t)
                        orderby t.DerivedTypes.Count descending
                        select t;

            _derivedTypes = UntangledTypeCollection.FromEnumeable(types);
        }

        UntangledTypeCollection _derivedTypes;


        public UntangledTypeCollection Interfaces { get { return _interfaces; } }

        readonly UntangledTypeCollection _interfaces;


        public string DisplayName { get { return _displayName; } }

        readonly string _displayName;

        public UntangledType( UntangledContext context, UntangledAssembly assembly, Type type)
        {
            Context = context;
            Assembly = assembly;
            _displayName = ReflectionHelper.GetDisplayName(type);

            Type = type;

            var ifTypes = from t in type.GetInterfaces()
                          orderby t.Name
                          select new UntangledType(context, assembly, t);

            _interfaces = UntangledTypeCollection.FromEnumeable(ifTypes);
        }

        public override string ToString()
        {
            return Type.Namespace + "." + _displayName;
        }

    }
}
